package jzqb.controller.admin;

import haha.life.common.*;
import haha.life.normal.FileUtil;
import haha.life.normal.FileuploadUtils;
import haha.life.normal.RandomUtils;
import io.swagger.annotations.Api;
import jzqb.annotation.PermissionCheck.PermissionCheck;
import jzqb.bo.AdminQueryBo;
import jzqb.common.Result;
import jzqb.po.QBZSPo;
import jzqb.service.AdminQBZSService;
import jzqb.service.MonitorService;
import jzqb.vo.Field;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

@RestController
@RequestMapping("/adminQBZS")
@Api(tags = "后台情报资源控制层")
public class AdminQBZSController {

    @Autowired
    private AdminQBZSService adminQBZSService;

    @Value("${filePath.fileTemPResource}")
    private String fileTemPResource;

    @Value("${filePath.batch_Import_DIR}")
    private String batch_Import_DIR;

    @Value("${filePath.updFileExcelPath}")
    private String updFileExcelPath;

    @Autowired
    private MonitorService monitorService;

    @Autowired
    private ExcelResolve excelResolve;


    //新建情报资源
    @PermissionCheck(permissionTypeList  ={PermissionTypeTool.business_mgt})
    @PostMapping(value = "insertQBZS")
    public Result insertQBZS(@RequestBody QBZSPo qbzsPo,HttpServletRequest request){
        Boolean result = adminQBZSService.insertQBZS(qbzsPo);
        if(result){
            Boolean insertRes = true;
            try {
                insertRes = monitorService.record(request,new MonitorTypeTool().getAddFile(),qbzsPo.getTitle(), "情报资源库");
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
            if(insertRes){
                return Result.succ("新建情报资源成功");
            }
        }
        return Result.fail("新建情报资源失败");
    }

    //修改情报资源
    @PermissionCheck(permissionTypeList  ={PermissionTypeTool.business_mgt})
    @PostMapping(value = "updateQBZS")
    public Result updateQBZS(@RequestBody QBZSPo qbzsPo,HttpServletRequest request){
        Boolean result = adminQBZSService.updateQBZS(qbzsPo);
        if(result){
            Boolean insertRes = true;
            try {
                insertRes = monitorService.record(request,new MonitorTypeTool().getEditFile(),qbzsPo.getTitle(), "情报资源库");
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
            if(insertRes){
                return Result.succ("修改情报资源成功");
            }
        }
        return Result.fail("修改情报资源失败");
    }

    //删除情报资源
    @PermissionCheck(permissionTypeList  ={PermissionTypeTool.business_mgt})
    @PostMapping(value = "deleteQBZS")
    public Result deleteQBZS(@RequestBody QBZSPo qbzsPo,HttpServletRequest request){
        Boolean result = adminQBZSService.deleteQBZS(qbzsPo);
        if(result){
            Boolean insertRes = true;
            try {
                insertRes = monitorService.record(request,new MonitorTypeTool().getDeleteFile(),qbzsPo.getTitle(), "情报资源库");
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
            if(insertRes){
                return Result.succ("删除情报资源成功");
            }
        }
        return Result.fail("删除情报资源失败");
    }

    //查询情报资源
    @PermissionCheck(permissionTypeList  ={PermissionTypeTool.business_mgt})
    @GetMapping(value = "queryQBZS")
    public Result queryQBZS( @RequestParam("searchWay") String searchWay,
                             @RequestParam("keyWord") String keyWord,
    @RequestParam("standardType[]") String[] standardType,
    @RequestParam("page") int page,
    @RequestParam("pageSize") int pageSize
    ){
        AdminQueryBo bo = new AdminQueryBo();
        bo.setSearchWay(searchWay);
        bo.setKeyWord(keyWord);
        bo.setStart((page - 1) * pageSize);
        bo.setEnd(pageSize);
        bo.setStandardType(standardType);
        List<QBZSPo> list = adminQBZSService.queryQBZS(bo);
        Integer total = adminQBZSService.count(bo).intValue();
        CutPageBean cutPageBean = new CutPageBean<>();
        cutPageBean.initCutPage(total, pageSize, list);
        return Result.succ(cutPageBean);
    }

    //临时上传
    @PermissionCheck(permissionTypeList  ={PermissionTypeTool.business_mgt})
    @RequestMapping(value = "/tempUpload")
    public Result tempUpload(@RequestParam("file") MultipartFile file) {
        //获取文件名
        String fileName =file.getOriginalFilename();
        String randDir = RandomUtils.getDirByName(fileName);
        String filePath = new File(fileTemPResource,randDir).toString();
        try {
            //执行保存(文件,目录,文件名)
            FileUtil.saveFile(file, filePath, fileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Result.succ(fileName);
    }

    //下载模板
    @RequestMapping(value = "getTemplate")
    public void getTemplate( HttpServletResponse resp,HttpServletRequest request){
        String dbCode = request.getParameter("dbCode");
        String realPath = "";   //源文件URL
        if("JZQBZS".equals(dbCode)){
            realPath = "static/ExcelTemplates/JZQBZS.xlsx";
        }
        if("JZCG".equals(dbCode)){
            realPath = "static/ExcelTemplates/JZCG.xlsx";
        }
        if("JZZY".equals(dbCode)){
            realPath = "static/ExcelTemplates/JZZY.xlsx";
        }
        if("YQTZTWX".equals(dbCode)){
            realPath = "static/ExcelTemplates/YQTZTWX.xlsx";
        }
        //- 准备需要下载的文件的文件名
        String fileName = realPath.substring(realPath.lastIndexOf("/") + 1);
        //- 设置浏览器的支持下载
        try {
            resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        //- 获取到下载到的文件的输入流
        InputStream in = this.getClass().getClassLoader().getResourceAsStream(realPath);
        //- 创建一个缓冲区用来写入流
        int len = 0;
        byte[] bytes = new byte[1024];
        //- 获取OutputStream对象
        ServletOutputStream outputStream = null;
        try {
            outputStream = resp.getOutputStream();//- 将FileOutputStream对象的流写入到先前创建的buffer缓冲区中,使用OutputStream对象将buffer缓冲区中的数据输出到自己的客户端中
            while ((len = in.read(bytes)) > 0) {
                outputStream.write(bytes, 0, len);
            }
            outputStream.close();
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //批量导入文件
    @RequestMapping(value = "batchImport")
    public Result batchImport(@RequestParam("file") MultipartFile file,HttpServletRequest request) throws Exception {
        long startTime = System.currentTimeMillis();
        //获取插入表及位置
        String dbCode = request.getParameter("dbCode");
        //获取文件名
        String fileName = file.getOriginalFilename();
        String dirName = RandomUtils.getRandomString(5) + "_" + fileName.substring(0,fileName.lastIndexOf("."));
        String dirPath = batch_Import_DIR + "\\" + dirName;
        String absPath = dirPath + "\\" + fileName;
        FileUtil.saveFile(file,dirPath,fileName);
        //解压文件并储存文件
        unZip(new File(absPath),absPath.substring(0,absPath.lastIndexOf("\\")));
        Result res = checkZipedDir(absPath.substring(0,absPath.lastIndexOf(".")),dbCode);
        long endTime = System.currentTimeMillis();
        System.out.println("批量上传总耗时：" + (endTime - startTime) +" ms");
        Boolean insertRes = true;
        String tableName = "";
        switch (dbCode) {
            case "JZQBZS":
                tableName = "情报资源库";
                break;
            case "JZCG":
                tableName = "研究成果库";
                break;
            case "JZZY":
                tableName = "情报自用库";
                break;
            case "YQTZTWX":
                tableName = "专题文献库";
                break;
            default:
                tableName = "";
        }
        if(res.getCode() == 200){
            try {
                insertRes = monitorService.record(request,new MonitorTypeTool().getAddFileBatch(),res.getData().toString(), tableName);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
        return res;
    }

    /**
     * 后端解压前端传输的 zip 压缩包,并在当前目录解压
     * @param srcFile zip压缩包
     * @param destDirPath 解压到哪里
     * @throws RuntimeException 运行时异常
     */
    public static void unZip(File srcFile, String destDirPath) throws RuntimeException {
        long start = System.currentTimeMillis();
        // 判断源文件是否存在
        if (!srcFile.exists()) {
            throw new RuntimeException(srcFile.getPath() + "所指文件不存在");
        }
        // 开始解压
        ZipFile zipFile = null;
        try {
            zipFile = new ZipFile(srcFile, Charset.forName("GBK"));
            Enumeration<?> entries = zipFile.entries();
            while (entries.hasMoreElements()) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                System.out.println("开始解压:" + entry.getName());
                // 如果是文件夹，就创建个文件夹
                if (entry.isDirectory()) {
                    String dirPath = destDirPath + "/" + entry.getName();
                    File dir = new File(dirPath);
                    dir.mkdirs();
                } else {
                    // 如果是文件，就先创建一个文件，然后用io流把内容copy过去
                    File targetFile = new File(destDirPath + "/" + entry.getName());
                    // 保证这个文件的父文件夹必须要存在
                    if(!targetFile.getParentFile().exists()){
                        targetFile.getParentFile().mkdirs();
                    }
                    targetFile.createNewFile();
                    // 将压缩文件内容写入到这个文件中
                    InputStream is = zipFile.getInputStream(entry);
                    FileOutputStream fos = new FileOutputStream(targetFile);
                    int len;
                    byte[] buf = new byte[1024*2];
                    while ((len = is.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                    }
                    // 关流顺序，先打开的后关闭
                    fos.close();
                    is.close();
                }
            }
            long end = System.currentTimeMillis();
            System.out.println("解压完成，耗时：" + (end - start) +" ms");
        } catch (Exception e) {
            throw new RuntimeException("unzip error from ZipUtils", e);
        } finally {
            if(zipFile != null){
                try {
                    zipFile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 检测解压后的文件
     * 读取excel
     * ---------存在excel?----读取每一行-----存在文件名字?----能在对应目录下找到文件?---遍历完成后,返回文件完整性校验结果
     *             |                          |                 |
     *       文件不完整异常                   pass          资源文件不完整
     */
    public  Result checkZipedDir(String tempDir,String dbCode) throws Exception {
        File file = new File(tempDir);
        File[] files=file.listFiles();
        boolean excelExist = false;
        boolean allFileExist = true;
        String uploadExcel ="";
        String excelPath = "";
        String lostFile = "";

        //------------------------------检测1：excel文件是否存在----------------------------------
        for (int i = 0; i < files.length; i++) {
            String fileName = files[i].getName();
            if (new File(tempDir,fileName).isFile()){
                if (fileName.substring(fileName.lastIndexOf(".")).toUpperCase().equals(".XLSX") || fileName.substring(fileName.lastIndexOf(".")).toUpperCase().equals(".XLS")){
                    uploadExcel = fileName.substring(0,fileName.lastIndexOf("."));
                    if(!uploadExcel.equals(dbCode))return Result.fail("上传文件的Excel与选择的数据库不相符！");
                    excelPath = tempDir + "\\" + fileName;
                    excelExist = true;
                    break;
                }
            }
        }
        if (excelExist){
//            String fields = "标题,作者,文献来源,发布日期,年,领域,分类,SYS_FLD_DIGITFILENAME";// 与excel模板中的红色字段对应
//            if("JZQBZS".equals(dbCode)) fields = "标题,作者,文献来源,发布日期,年,领域,SYS_FLD_DIGITFILENAME";// 与excel模板中的红色字段对应
            String fields = "题名,SYS_FLD_DIGITFILENAME,领域";
            if("YQTZTWX".equals(dbCode)){
                fields = "专题集ID,专题ID,题名,SYS_FLD_DIGITFILENAME,领域";
            }
            ArrayList<String> allFileds = new ArrayList<String>();
            for (String s :fields.split(",")){
                allFileds.add(s);
            }
            //----------------------------检测2 ：是否存在空列或内容为空--------------------------------
            JSONArray jsonArray = null;
            try {
                jsonArray = excelResolve.readExcel(new File(excelPath));
                if (jsonArray.size()==0){
                    return Result.fail("excel内容为空");
                }
            }catch (Exception e){
                return Result.fail("excel存在空列");
            }
            //------------------------------检测3 ：是否存在必要表头--------------------------------------
            Object[] keysSet = jsonArray.getJSONObject(0).keySet().toArray();
            ArrayList<String> keysList = new ArrayList<String>();
            for ( Object i:keysSet){
                keysList.add(i.toString());
            }
            for (String i :allFileds){
                if (!keysList.contains(i)){
                    return Result.fail("excel缺少必要表头:" + i);
                }
            }
            //-----------------------------检测4: 是否每行都存在必要表头的数据---------------------------------
            jsonArray.getJSONObject(0).keySet();
            Boolean exist = true;
            for(int i=0;i<jsonArray.size();i++) {
                for (String j :allFileds){
                    exist = isExist(jsonArray.getJSONObject(i).get(j));
                    if(!exist) return Result.fail(j+"为空:第"+(i+1)+ "行");
                }
                //---------------------------检测5 ：是否excel中的文件全部都存在-----------------------------
//                String dbCode = jsonArray.getJSONObject(i).get("数据库编码").toString();
                if (isExist(jsonArray.getJSONObject(i).get("SYS_FLD_DIGITFILENAME"))) {
                    String digitFileName = jsonArray.getJSONObject(i).get("SYS_FLD_DIGITFILENAME").toString();
                    File digitFile = new File(new File(tempDir, dbCode), digitFileName);
                    if (!digitFile.exists()) {
                        allFileExist = false;
                        lostFile = digitFile.getName();
                        break;
                    }
                }
                //---------------------------检测6 ：是否excel中的图片全部都存在-----------------------------
                if("JZCG".equals(dbCode) || "JZZY".equals(dbCode)){
                    if (isExist(jsonArray.getJSONObject(i).get("封面"))){
                        String digitFileName = jsonArray.getJSONObject(i).get("封面").toString();
                        File digitFile = new File(new File(tempDir,dbCode),digitFileName);
                        if (!digitFile.exists()){
                            allFileExist = false;
                            lostFile = digitFile.getName();
                            break;
                        }
                    }
                }
            }
            if (allFileExist){
                return  insert(tempDir,excelPath,dbCode);
            }else{
                return  Result.fail("资源文件不完整:" + lostFile);
            }
        }else{
            return  Result.fail("缺少Excel文件");
        }
    }

    /**
     * 通过读取Excel插入数据库
     * @param tempDir
     * @param excelPath
     * @param dbCode
     * @return
     * @throws Exception
     */
    public Result insert(String tempDir,String excelPath,String dbCode) throws Exception {
        JSONArray jsonArray = excelResolve.readExcel(new File(excelPath));
        boolean OK = true;
        for(int i=0;i<jsonArray.size();i++) {
            JSONObject obj = jsonArray.getJSONObject(i);
            String field = obj.getString("领域");
            String fieldCode = "";
            if (Field.ONE.getShowName().equals(field)) {
                fieldCode = Field.ONE.getDbCode();
            } else if (Field.TWO.getShowName().equals(field)) {
                fieldCode = Field.TWO.getDbCode();
            } else if (Field.THREE.getShowName().equals(field)) {
                fieldCode = Field.THREE.getDbCode();
            } else if (Field.FOUR.getShowName().equals(field)) {
                fieldCode = Field.FOUR.getDbCode();
            } else if (Field.FIVE.getShowName().equals(field)) {
                fieldCode = Field.FIVE.getDbCode();
            } else if (Field.SIX.getShowName().equals(field)) {
                fieldCode = Field.SIX.getDbCode();
            } else if (Field.SEVEN.getShowName().equals(field)) {
                fieldCode = Field.SEVEN.getDbCode();
            } else if (Field.EIGHT.getShowName().equals(field)) {
                fieldCode = Field.EIGHT.getDbCode();
            } else {
                fieldCode =   Field.EIGHT.getDbCode();
            }
            obj.put("领域",fieldCode);
            boolean res = adminQBZSService.batchImport(tempDir,obj,dbCode);
            if (!res){
                OK = false;
                break;
            }
        }
        if (OK){
            //存储EXCEL
            File oldFile = new File(excelPath);
            String fileName = oldFile.getName();
            fileName = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date())+"_"+fileName;
            File newFile = new File(updFileExcelPath + File.separator + fileName);
            oldFile.renameTo(newFile);
            //删除临时目录
            boolean deleteRes = FileUtil.deleteFolder(new File(tempDir).getParentFile().toString());
            if (deleteRes){
                return Result.succ(jsonArray.size());
            }else{
                return Result.succ("删除解压文件失败");
            }
        }else{
            return Result.fail("错误:可能的原因是:后台错误;excel存在错误表头");
        }
    }

    /**
     * 判断对象是否为空
     * @param obj
     * @return
     */
    public static Boolean isExist(Object obj){
        if(("").equals(obj) || obj == null)return false;
        return true;
    }


}

